﻿#include "common.h"
#include "MainWindow.h"

using namespace std;

#ifndef ENABLE_Cross_Platform_DelSuffixFile
#ifdef __ANDROID__
#include <dirent.h>

int DelSuffixFile(const string rootpath, const string strSuffix, bool& bStop, int level)
{
	DIR* pDir;
	struct dirent* pFileInfo;
	struct stat statInfo;
	pDir = opendir(rootpath.c_str());
	while ((pFileInfo = readdir(pDir)) != NULL) {
		if (bStop) return 2;
		if (pFileInfo->d_name[0] == '.')
			continue;

		string strFilePath(rootpath + "/" + pFileInfo->d_name);
		if (stat(strFilePath.c_str(), &statInfo) >= 0)
		{
			if (S_ISDIR(statInfo.st_mode))
			{
				if (--level > 0)
					DelSuffixFile(pFileInfo->d_name, strSuffix, bStop, level);
			}
			else
			{
				size_t lenFileName = strlen(pFileInfo->d_name);
				if (lenFileName > strSuffix.length() && pFileInfo->d_name[lenFileName - strSuffix.length() - 1] == '.'
					&& &pFileInfo->d_name[lenFileName - strSuffix.length()] == strSuffix)
				{
					remove(strFilePath.c_str());
				}
			}
		}
	}
	(void)closedir(pDir);
	return 0;
}

#else

int DelSuffixFile(const string rootpath, const string strSuffix, bool& bStop, int level)
{
	struct _finddata_t fileinfo;
	struct _stat buf;
	int	result;
	string path = rootpath + "/*.*";
	int64_t hff = _findfirst(path.c_str(), &fileinfo);
	if (-1 == hff) {
		printf("filepath error/n");
		return -1;
	}

	do
	{
		if (bStop) return 2;
		char* filename = fileinfo.name;
		if (filename[0] == '.') {				// jump "." and ".." pFileInfo
			continue;
		}
		path = rootpath + "/" + filename;
		result = _stat(path.c_str(), &buf);
		if (result != 0)
		{
			perror("$$$ Problem getting information");
		}
		else
		{
			if (buf.st_mode == 16895 || buf.st_mode == 16749)					// Directory _S_IFDIR
			{
				if (--level > 0)
					DelSuffixFile(path, strSuffix, bStop, level);
			}
			else if (buf.st_mode == 33206 || buf.st_mode == 33060)				// File
			{
				size_t lenFileName = strlen(filename);
				if (lenFileName > strSuffix.length() && filename[lenFileName - strSuffix.length() - 1] == '.'
					&& &filename[lenFileName - strSuffix.length()] == strSuffix)
				{
					remove(path.c_str());
				}
			}
			else
			{
				printf("$$$ 'st_mode' ERROR! /n");
				return -1;
			}
		}
	} while (0 == _findnext(hff, &fileinfo));
	_findclose(hff);
	return 0;
}

#endif

#else

int DelSuffixFile(const QString strPath, const QString strSuffix = "chapter", bool& bStop, int level)
{
	if (strPath.isEmpty())
		return -1;
	QDir dir;
	dir.setPath(strPath);

	if (!dir.exists()) {
		return -2;
	}
	dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot); //设置过滤
	QFileInfoList fileList = dir.entryInfoList(); // 获取所有的文件信息
	foreach(QFileInfo pFileInfo, fileList)
	{ //遍历文件信息
		if (bStop) return 2;
		if (pFileInfo.isFile()) { // 是文件，删除
			if (pFileInfo.suffix() == strSuffix)
				pFileInfo.dir().remove(pFileInfo.fileName());
		}
		else { // 递归删除
			if (--level > 0)
				DelSuffixFile(pFileInfo.absoluteFilePath(), strSuffix, bStop, level);
		}
	}
	//return dir.rmpath(dir.absolutePath()); // 删除文件夹
	return 0;
}
#endif

#ifdef __ANDROID__

bool requestPermission() {
	QStringList strList;
	strList <<
		"android.permission.ACCESS_NOTIFICATION_POLICY" <<
		"android.permission.READ_EXTERNAL_STORAGE" <<
		"android.permission.WRITE_EXTERNAL_STORAGE" <<
		"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" <<
		"android.permission.WRITE_SECURE_SETTINGS" <<
		"android.permission.INTERNAL_SYSTEM_WINDOW" <<
		"android.permission.SYSTEM_ALERT_WINDOW" <<
		"android.permission.android.permission.RESTART_PACKAGES" <<
		"android.permission.WRITE_SETTINGS";
	for (auto& str : strList)
	{
		if (QtAndroid::checkPermission(str) == QtAndroid::PermissionResult::Denied)
		{
			QtAndroid::requestPermissionsSync(strList);
			break;
		}
	}

	for (auto& str : strList)
	{
		if (QtAndroid::checkPermission(str) == QtAndroid::PermissionResult::Denied)
		{
			return false;
		}
	}
	return true;
}


#include <jni.h>

extern MainWindow* g_pMainWindow;

extern "C" {
	JNIEXPORT void JNICALL Java_qt_java_MainActivity_CallNativeOnPause(JNIEnv* env, jobject thiz)
	{
		qDebug() << "C++ CppOnPause";
		if (g_pMainWindow)
		{
			g_pMainWindow->CallNativeOnPause();
		}
	}

	JNIEXPORT void JNICALL Java_qt_java_MainActivity_CallNativeOnResume(JNIEnv* env, jobject thiz)
	{
		qDebug() << "C++ CppOnResume";
		if (g_pMainWindow)
		{
			g_pMainWindow->CallNativeOnResume();
		}
	}
}

#endif

QString getUrlFullPath(QString strUrl, QString strUrlTail)
{
	if (strUrlTail.indexOf("http") == -1 && strUrl.length() > WEB_ADDRESS_HEAD_FIND_LENGTH)
	{
		if (strUrlTail.left(2) == "//")
		{
			strUrl = strUrl.left(strUrl.indexOf("//"));
		}
		else if (strUrlTail[0] == '/')
		{
			strUrl = strUrl.left(strUrl.indexOf('/', WEB_ADDRESS_HEAD_FIND_LENGTH));
		}
		else if (strUrl[strUrl.length() - 1] != '/')
		{
			strUrl = strUrl.left(strUrl.lastIndexOf('/') + 1);
		}
		strUrlTail = strUrl + strUrlTail;
	}
	return strUrlTail;
}

QString GetListWidgetBookItemString(sBookInfo& book)
{
	QString strBookInfo(book.name.left(book.name.lastIndexOf('.')) + "\n"
		+ book.strAuthor + " " + book.strUpdateTime + " " + book.path + "\n"
		+ book.strChapterHead + " " + QString::number((book.chapter + 1) * 100 / book.maxChapter) + "% " + book.status);
	return strBookInfo;
}

string GetWebHeadPropertyContent(string& strText, string str)
{
	string::size_type index = 0, tail = 0;
	index = strText.find(str.c_str());
	if (index != string::npos)
	{
		index += str.size() + 8;
		index = strText.find('\"', index);
		if (index != string::npos)
		{
			index++;
			tail = strText.find('\"', index);
			if (tail != string::npos)
			{
				return strText.substr(index, tail - index);
			}
		}
	}
	return "";
}

string GetHtmlText(string& strText, string str)
{
	string::size_type index = 0;
	while ((index = strText.find(str.c_str(), index)) != string::npos)
	{
		auto tail = strText.find("\n", index);
		auto line = strText.substr(index, tail - index);
		static std::regex e(str + ".*>([^<]+)<");
		std::smatch cm;
		std::regex_search(line, cm, e, std::regex_constants::match_default);
		if (cm.size() > 1)
		{
			return cm[1].str();
		}
		index = tail;
	}
	return "";
}

void GetWebBookInfo(string& strText, sBookInfo& book)
{
	//获取网书的作者和最后更新时间
	smatch sm;
	if (regex_search(strText, sm, regex("book_name\" content=\"(.*?)\"")))
		book.name = QString::fromStdString(sm[1].str());
	else if (regex_search(strText, sm, regex("\"info_title\">(.*?)<")))
		book.name = QString::fromStdString(sm[1].str());
	else
	{
		size_t head = 0;
		set<string> book_list;
		std::cmatch cm;
		while (regex_search(strText.c_str() + head, cm, regex("《(.*?)》")))
		{
			head += cm.position() + cm.length() + 1;
			book_list.insert(cm[1].str());
		}
		for (auto& book_name : book_list)
		{
			//cout << book_name << endl;
			//cout << UTF8ToANSI(book_name.c_str()).constData() << endl;
			auto re = ">" + book_name + "<";
			smatch sm2;
			if (regex_search(strText, sm2, regex(re)))
			{
				book.name = QString::fromStdString(book_name);
				break;
			}
		}
	}
	const auto dotWeb = ".web";
	if (book.name.indexOf(dotWeb) == -1)book.name += dotWeb;
	if (regex_search(strText, sm, regex("author\" content=\"(.*?)\"")))
		book.strAuthor = QString::fromStdString(sm[1].str());
	else if (regex_search(strText, sm, regex("作.*者：(.*?)<")))
		book.strAuthor = QString::fromStdString(sm[1].str());
	if (regex_search(strText, sm, regex("status\" content=\"(.*?)\"")))
		book.status = QString::fromStdString(sm[1].str());
	else if (regex_search(strText, sm, regex("状.*态：(.*?)<")))
		book.status = QString::fromStdString(sm[1].str());
	if (regex_search(strText, sm, regex("update_time\" content=\"(.*?)\"")))
		book.strUpdateTime = QString::fromStdString(sm[1].str());
	else if (regex_search(strText, sm, regex("更.*新：\\D*([0-9- :]{10,})")))
		book.strUpdateTime = QString::fromStdString(sm[1].str());
}

int BMSearch(const char* strSrc, int lenSrc, const char* strSub, int lenSub)
{
	int right[BM_SEARCH_TABLE_LENGTH];
	for (int i = 0; i < BM_SEARCH_TABLE_LENGTH; i++)
	{
		right[i] = -1;
	}
	for (int i = 0; i < lenSub; i++)
	{
		right[(unsigned char)strSub[i]] = i;
	}

	int skip;
	for (int i = 0; i <= lenSrc - lenSub; i += skip)
	{
		skip = 0;
		for (int j = lenSub - 1; j >= 0; j--)
		{
			if (strSub[j] != strSrc[i + j])
			{
				skip = j - right[(unsigned char)strSrc[i + j]];
				if (skip < 1)
					skip = 1;
				break;
			}
		}
		if (skip == 0)
			return i;
	}
	return -1;
}

bool isUTF8(const char* rawtext, size_t rawtextlen)
{
	size_t score = 0;
	size_t i = 0;
	size_t goodbytes = 0, asciibytes = 0;
	size_t len = (int)strlen(rawtext);
	if (len < rawtextlen) rawtextlen = len;

	for (i = 0; i < rawtextlen; i++)
	{
		if ((rawtext[i] & 0x7F) == rawtext[i])
		{
			//最高位是0的ASCII字符
			//一位编码的情况
			asciibytes++;
		}
		else if ((char)-64 <= rawtext[i] && rawtext[i] <= (char)-33
			//两位编码的情况,第一位11000000--11011111
			//后一位跟10000000--10111111
			&& i + 1 < len
			&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65)
		{
			goodbytes += 2;
			i++;
		}
		else if ((char)-32 <= (char)rawtext[i] && rawtext[i] <= (char)-17 &&
			i + 2 < len &&
			(char)-128 <= (char)rawtext[i + 1] && (char)rawtext[i + 1] <= (char)-65 &&
			(char)-128 <= (char)rawtext[i + 2] && (char)rawtext[i + 2] <= (char)-65)
		{
			goodbytes += 3;
			i += 2;
		}
		else if ((char)-16 <= rawtext[i] && rawtext[i] <= (char)-9
			//四位编码的情况,第一位11110000--11110111
			//后三位跟10000000--10111111
			&& i + 3 < len
			&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65
			&& (char)-128 <= rawtext[i + 2] && rawtext[i + 2] <= (char)-65
			&& (char)-128 <= rawtext[i + 3] && rawtext[i + 3] <= (char)-65)

		{
			goodbytes += 4;
			i += 3;
		}
		else if ((char)-8 <= rawtext[i] && rawtext[i] <= (char)-5
			//五位编码的情况,第一位11111000--11111011
			//后四位跟10000000--10111111
			&& i + 4 < len
			&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65
			&& (char)-128 <= rawtext[i + 2] && rawtext[i + 2] <= (char)-65
			&& (char)-128 <= rawtext[i + 3] && rawtext[i + 3] <= (char)-65
			&& (char)-128 <= rawtext[i + 4] && rawtext[i + 4] <= (char)-65)
		{
			goodbytes += 5;
			i += 4;
		}
		else if ((char)-4 <= rawtext[i] && rawtext[i] <= (char)-3
			//六位编码的情况,第一位11111100--11111101
			//后五位跟10000000--10111111
			&& i + 5 < len
			&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65
			&& (char)-128 <= rawtext[i + 2] && rawtext[i + 2] <= (char)-65
			&& (char)-128 <= rawtext[i + 3] && rawtext[i + 3] <= (char)-65
			&& (char)-128 <= rawtext[i + 4] && rawtext[i + 4] <= (char)-65
			&& (char)-128 <= rawtext[i + 5] && rawtext[i + 5] <= (char)-65)
		{
			goodbytes += 6;
			i += 5;
		}
		else
		{
			return false;
		}
	}
	if (asciibytes >= rawtextlen)
	{
		return true;
	}
	score = 100 * goodbytes / (rawtextlen - asciibytes);
	//如果匹配率达到98%以上,则成功
	//允许一部分脏数据
	if (score > 98)
	{
		return true;
	}
	else if (score > 95 && goodbytes > 30)
	{
		return true;
	}
	else
	{
		return false;
	}
}


int GetUTF8CharSize(char* rawtext, int rawtextlen)
{
	int i = 0;
	if ((rawtext[i] & 0x7F) == rawtext[i])
	{
		//最高位是0的ASCII字符
		//一位编码的情况
		return 1;
	}
	else if ((char)-64 <= rawtext[i] && rawtext[i] <= (char)-33
		//两位编码的情况,第一位11000000--11011111
		//后一位跟10000000--10111111
		&& i + 1 < rawtextlen
		&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65)
	{
		return 2;
	}
	else if ((char)-32 <= (char)rawtext[i] && rawtext[i] <= (char)-17 &&
		i + 2 < rawtextlen &&
		(char)-128 <= (char)rawtext[i + 1] && (char)rawtext[i + 1] <= (char)-65 &&
		(char)-128 <= (char)rawtext[i + 2] && (char)rawtext[i + 2] <= (char)-65)
	{
		return 3;
	}
	else if ((char)-16 <= rawtext[i] && rawtext[i] <= (char)-9
		//四位编码的情况,第一位11110000--11110111
		//后三位跟10000000--10111111
		&& i + 3 < rawtextlen
		&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65
		&& (char)-128 <= rawtext[i + 2] && rawtext[i + 2] <= (char)-65
		&& (char)-128 <= rawtext[i + 3] && rawtext[i + 3] <= (char)-65)

	{
		return 4;
	}
	else if ((char)-8 <= rawtext[i] && rawtext[i] <= (char)-5
		//五位编码的情况,第一位11111000--11111011
		//后四位跟10000000--10111111
		&& i + 4 < rawtextlen
		&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65
		&& (char)-128 <= rawtext[i + 2] && rawtext[i + 2] <= (char)-65
		&& (char)-128 <= rawtext[i + 3] && rawtext[i + 3] <= (char)-65
		&& (char)-128 <= rawtext[i + 4] && rawtext[i + 4] <= (char)-65)
	{
		return 5;
	}
	else if ((char)-4 <= rawtext[i] && rawtext[i] <= (char)-3
		//六位编码的情况,第一位11111100--11111101
		//后五位跟10000000--10111111
		&& i + 5 < rawtextlen
		&& (char)-128 <= rawtext[i + 1] && rawtext[i + 1] <= (char)-65
		&& (char)-128 <= rawtext[i + 2] && rawtext[i + 2] <= (char)-65
		&& (char)-128 <= rawtext[i + 3] && rawtext[i + 3] <= (char)-65
		&& (char)-128 <= rawtext[i + 4] && rawtext[i + 4] <= (char)-65
		&& (char)-128 <= rawtext[i + 5] && rawtext[i + 5] <= (char)-65)
	{
		return 6;
	}
	return 0;
}

QByteArray ANSIToUTF8(const char* strSrc)
{
	QTextCodec* utf8 = QTextCodec::codecForName("utf-8");
	QTextCodec* locale = QTextCodec::codecForLocale();
	QTextCodec::setCodecForLocale(utf8);
	QTextCodec* gbk = QTextCodec::codecForName("gbk");

	//gbk -> utf8

	//1. gbk to unicode
	QString strUnicode = gbk->toUnicode(strSrc);
	//2. unicode -> utf-8
	QByteArray utf8_bytes = utf8->fromUnicode(strUnicode);
	QTextCodec::setCodecForLocale(locale);
	return utf8_bytes;
}

QByteArray UTF8ToANSI(const char* strSrc)
{
	QTextCodec* utf8 = QTextCodec::codecForName("UTF-8");
	QTextCodec* locale = QTextCodec::codecForLocale();
	QTextCodec::setCodecForLocale(utf8);
	QTextCodec* gbk = QTextCodec::codecForName("gbk");
	//utf8 -> gbk

	//1. utf8 -> unicode

	QString strUnicode = utf8->toUnicode(strSrc);

	//2. unicode -> gbk, 得到QByteArray

	QByteArray gb_bytes = gbk->fromUnicode(strUnicode);
	QTextCodec::setCodecForLocale(locale);
	return gb_bytes;
}

QString ToUnicode(const char* strSrc, const char* strCharset)
{
	QTextCodec* textcodec = QTextCodec::codecForName(strCharset);
	QTextCodec* locale = QTextCodec::codecForLocale();
	QTextCodec::setCodecForLocale(textcodec);
	//1. utf8 -> unicode
	QString strUnicode(textcodec->toUnicode(strSrc));
	QTextCodec::setCodecForLocale(locale);
	return strUnicode;
}

string GetCharset(const string& str)
{
	if (isUTF8(str.c_str(), 0x400))
		return "utf-8";
	else
		return "gbk";
	//string strCharset = "charset";
	//string::size_type index = str.find(strCharset);
	//if (index != string::npos)
	//{
	//	index += strCharset.length();
	//	while (str[index] < 'A')index++;
	//	strCharset.clear();
	//	for (;; index++)
	//	{
	//		char s = str[index] | 32;
	//		if ((s >= '0' && s <= '9') || (s >= 'a' && s <= 'z') || s == '-')
	//			strCharset += s;
	//		else
	//		{
	//			if (strCharset != "utf-8")
	//			{
	//				if (isUTF8(&str[index]))
	//					return "utf-8";
	//			}
	//			return strCharset;
	//		}
	//	}
	//}
	//return "utf-8";
}

QString& ModifySymbol(QString& str)
{
	for (auto& qchar : str)
	{
		if (!(qchar.isLetterOrNumber() || qchar.isMark()))
		{
			qchar = '_';
		}
	}
	return str;
}

QString& DeleteSymbol(QString& str)
{
	QString strRet;
	for (auto& qchar : str)
	{
		if (qchar.isLetterOrNumber() || qchar.isMark())
		{
			strRet.append(qchar);
		}
	}
	return str = strRet;
};

//中文数字转阿拉伯数字
int64_t chineseNum2num(const wstring& s)
{
	static const map<wchar_t, int> chineseNum{
		{L'零', 0},
		{ L'一', 1 },
		{ L'二', 2 },
		{ L'两', 2 },
		{ L'三', 3 },
		{ L'四', 4 },
		{ L'五', 5 },
		{ L'六', 6 },
		{ L'七', 7 },
		{ L'八', 8 },
		{ L'九', 9 },
		{ L'十', 10 },
		{ L'百', 100 },
		{ L'千', 1000 },
		{ L'万', 10000 },
		{ L'亿', 100000000 },
		{ L'壹', 1 },
		{ L'贰', 2 },
		{ L'叁', 3 },
		{ L'肆', 4 },
		{ L'伍', 5 },
		{ L'陆', 6 },
		{ L'柒', 7 },
		{ L'捌', 8 },
		{ L'玖', 9 },
		{ L'拾', 10 },
		{ L'佰', 100 },
		{ L'仟', 1000 },
		{ L'萬', 10000 },
		{ L'億', 100000000 },
		{ L'0', 0 },
		{ L'1', 1 },
		{ L'2', 2 },
		{ L'3', 3 },
		{ L'4', 4 },
		{ L'5', 5 },
		{ L'6', 6 },
		{ L'7', 7 },
		{ L'8', 8 },
		{ L'9', 9 } };

	wstring::size_type index = 0;
	int64_t result = 0, tmp = 0, hundred_million = 0, curr_digit = 0;
	// 从第一次遇到数字开始，后面的截断，比如：“第三十一章 测试”，会转为31
	while (index < s.length() && chineseNum.find(s[index]) == chineseNum.end())
	{
		index++;
	}

	//如果是纯数字，直接stoi返回
	auto tail = index;
	while (tail <= s.length() && s[tail] >= L'0' && s[tail] <= L'9')
	{
		tail++;
	}
	if (index != tail)
	{
		result = stoll(s.substr(index, tail - index));
		return result;
	}

	for (; index < s.length(); index++)
	{
		wchar_t curr_char = s[index];
		// 不管长度全面搜索数字
		auto it = chineseNum.find(curr_char);
		if (it == chineseNum.end())
		{
			break;
		}

		curr_digit = it->second;

		if (curr_digit == 100000000)//meet 「亿」 or 「億」
		{
			result = result + tmp;
			result = result * curr_digit;
			//get result before 「亿」 and store it into hundred_million
			//reset `result`
			hundred_million = hundred_million * 100000000 + result;
			result = 0;
			tmp = 0;
		}
		else
		{
			if (curr_digit == 10000)//meet 「万」 or 「萬」
			{
				result = result + tmp;
				result = result * curr_digit;
				tmp = 0;
			}
			else
			{
				if (curr_digit >= 10)//meet 「十」, 「百」, 「千」 or their traditional version
				{
					if (tmp == 0)
						tmp = 1;
					result = result + curr_digit * tmp;
					tmp = 0;
				}
				else
				{
					tmp = tmp * 10 + curr_digit;
				}
			}
		}
	}
	result += hundred_million + tmp;
	return result;
}

using sysclock_t = std::chrono::system_clock;

std::string CurrentDate()
{
	const int MAX_LOG_ONE_LINE_SIZE = 100;
	static char message[MAX_LOG_ONE_LINE_SIZE + 1] = { 0 };
	size_t len;
	time_t t;
	time(&t);
	len = strftime(message, MAX_LOG_ONE_LINE_SIZE, "%Y-%m-%d %H:%M:%S", localtime(&t));
	message[MAX_LOG_ONE_LINE_SIZE] = '\0';
	return std::string(message);
}

void SaveBookListInfo()
{
	QSettings set((BOOK_LIST_SAVE_DIR"BooksListInfo.info"), QSettings::IniFormat);
	set.setIniCodec(QTextCodec::codecForName("UTF-8"));
	set.clear();
	int i = 0;
	for (auto& book : m_listBookInfo)
	{
		set.setValue(QString::number(i) + "/name", book.name);
		set.setValue(QString::number(i) + "/path", book.path);
		set.setValue(QString::number(i) + "/author", book.strAuthor);
		set.setValue(QString::number(i) + "/updatetime", book.strUpdateTime);
		set.setValue(QString::number(i) + "/chapter", book.strChapterHead);
		set.setValue(QString::number(i) + "/maxChapter", book.maxChapter);
		set.setValue(QString::number(i) + "/status", book.status);
		set.setValue(QString::number(i) + "/sort", book.sort);
		set.setValue(QString::number(i) + "/utf8", book.utf8);
		i++;
	}
}

std::string ReadFileToString(const std::string& filename)
{
	std::ifstream ifs(filename, std::ios::binary);
	std::ostringstream oss;
	oss << ifs.rdbuf();
	return oss.str();
}

